package com.witmore.skyline.web.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.witmore.skyline.db.entity.AreaRegionDO;
import com.witmore.skyline.db.mapper.AreaRegionMapper;
import com.witmore.skyline.web.service.RegionDataImportService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 地区数据导入服务实现
 *
 * @author 豆子高
 * @since 2025-10-22
 */
@Slf4j
@Service
public class RegionDataImportServiceImpl implements RegionDataImportService {

    @Autowired
    private AreaRegionMapper areaRegionMapper;
    
    // 直辖市列表（省级编码）
    private static final Set<String> DIRECT_MUNICIPALITIES = new HashSet<>(
        Arrays.asList("110000", "120000", "310000", "500000")  // 北京、天津、上海、重庆
    );

    @Override
    @Transactional(rollbackFor = Exception.class)
    public RegionImportResult importRegionDataFromJson() {
        long startTime = System.currentTimeMillis();
        
        try {
            // 1. 检查是否已有数据，如果有则抛出异常
            LambdaQueryWrapper<AreaRegionDO> checkWrapper = new LambdaQueryWrapper<>();
            long existingCount = areaRegionMapper.selectCount(checkWrapper);
            if (existingCount > 0) {
                throw new RuntimeException(String.format("数据库中已存在 %d 条地区数据，请先调用清空接口清除数据后再导入", existingCount));
            }

            // 2. 读取JSON文件
            String jsonContent = readJsonFile();
            if (!StringUtils.hasText(jsonContent)) {
                return new RegionImportResult(0, 0, 0, 0, "JSON文件读取失败或为空");
            }

            // 3. 解析JSON数据
            JSONObject rootJson = JSON.parseObject(jsonContent);

            // 4. 解析并插入数据
            List<AreaRegionDO> regionList = new ArrayList<>();
            
            // 插入国家级数据
            AreaRegionDO country = parseCountryData(rootJson);
            regionList.add(country);
            
            // 解析省级数据
            JSONArray provinces = rootJson.getJSONArray("children");
            if (provinces != null) {
                for (int i = 0; i < provinces.size(); i++) {
                    JSONObject provinceJson = provinces.getJSONObject(i);
                    
                    // 插入省级数据
                    AreaRegionDO province = parseProvinceData(provinceJson, i + 1);
                    regionList.add(province);
                    
                    // 解析子级数据
                    JSONArray children = provinceJson.getJSONArray("children");
                    if (children != null) {
                        // 根据省份编码判断是否为直辖市
                        boolean isDirectMunicipality = DIRECT_MUNICIPALITIES.contains(province.getAdcode());
                        
                        if (isDirectMunicipality) {
                            // 直辖市：先创建市级数据，再创建区级数据
                            String cityCode = children.getJSONObject(0).getString("cityCode");
                            if (cityCode != null) {
                                // 创建市级数据（市辖区）
                                AreaRegionDO city = createMunicipalityCity(cityCode, province.getAdcode(), province.getName());
                                regionList.add(city);
                                
                                // 创建所有区级数据
                                for (int j = 0; j < children.size(); j++) {
                                    JSONObject districtJson = children.getJSONObject(j);
                                    AreaRegionDO district = parseDistrictData(districtJson, 
                                        province.getAdcode(), cityCode, j + 1);
                                    regionList.add(district);
                                }
                            }
                        } else {
                            // 普通省份：处理市级和区县级数据
                            for (int j = 0; j < children.size(); j++) {
                                JSONObject cityJson = children.getJSONObject(j);
                                
                                // 插入市级数据
                                AreaRegionDO city = parseCityData(cityJson, province.getAdcode(), j + 1);
                                regionList.add(city);
                                
                                // 解析区县级数据
                                JSONArray districts = cityJson.getJSONArray("children");
                                if (districts != null) {
                                    for (int k = 0; k < districts.size(); k++) {
                                        JSONObject districtJson = districts.getJSONObject(k);
                                        AreaRegionDO district = parseDistrictData(districtJson, 
                                            province.getAdcode(), city.getAdcode(), k + 1);
                                        regionList.add(district);
                                    }
                                }
                            }
                        }
                    }
                }
            }

            // 5. 批量插入数据
            int totalCount = regionList.size();
            int successCount = 0;
            int failCount = 0;
            
            // 分批次批量插入，每批500条
            int batchSize = 500;
            for (int i = 0; i < regionList.size(); i += batchSize) {
                int endIndex = Math.min(i + batchSize, regionList.size());
                List<AreaRegionDO> batchList = regionList.subList(i, endIndex);
                
                try {
                    // 使用MyBatis-Plus的批量插入
                    batchInsertRegions(batchList);
                    successCount += batchList.size();
                    log.info("批量插入地区数据成功，当前批次: {}-{}, 总进度: {}/{}", 
                        i + 1, endIndex, successCount, totalCount);
                } catch (Exception e) {
                    log.error("批量插入地区数据失败，批次: {}-{}", i + 1, endIndex, e);
                    failCount += batchList.size();
                }
            }

            long costTime = System.currentTimeMillis() - startTime;
            String message = String.format("导入完成！总计: %d, 成功: %d, 失败: %d, 耗时: %dms", 
                totalCount, successCount, failCount, costTime);
            
            log.info(message);
            return new RegionImportResult(totalCount, successCount, failCount, costTime, message);
            
        } catch (Exception e) {
            long costTime = System.currentTimeMillis() - startTime;
            log.error("地区数据导入失败", e);
            return new RegionImportResult(0, 0, 0, costTime, "导入失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int clearRegionData() {
        LambdaQueryWrapper<AreaRegionDO> wrapper = new LambdaQueryWrapper<>();
        int count = Math.toIntExact(areaRegionMapper.selectCount(wrapper));
        areaRegionMapper.delete(wrapper);
        return count;
    }

    @Override
    public RegionStatistics getRegionStatistics() {
        LambdaQueryWrapper<AreaRegionDO> wrapper = new LambdaQueryWrapper<>();
        
        wrapper.eq(AreaRegionDO::getLevel, 0);
        int countryCount = Math.toIntExact(areaRegionMapper.selectCount(wrapper));
        
        wrapper.clear();
        wrapper.eq(AreaRegionDO::getLevel, 1);
        int provinceCount = Math.toIntExact(areaRegionMapper.selectCount(wrapper));
        
        wrapper.clear();
        wrapper.eq(AreaRegionDO::getLevel, 2);
        int cityCount = Math.toIntExact(areaRegionMapper.selectCount(wrapper));
        
        wrapper.clear();
        wrapper.eq(AreaRegionDO::getLevel, 3);
        int districtCount = Math.toIntExact(areaRegionMapper.selectCount(wrapper));
        
        return new RegionStatistics(countryCount, provinceCount, cityCount, districtCount);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public RegionImportResult fillFullNames() {
        long startTime = System.currentTimeMillis();
        
        try {
            // 1. 获取所有地区数据
            List<AreaRegionDO> allRegions = areaRegionMapper.selectList(
                new LambdaQueryWrapper<AreaRegionDO>()
                    .eq(AreaRegionDO::getIsActive, true)
                    .orderByAsc(AreaRegionDO::getLevel)
            );
            
            if (allRegions.isEmpty()) {
                return new RegionImportResult(0, 0, 0, 0, "没有找到地区数据");
            }
            
            // 2. 构建 adcode -> region 的映射
            Map<String, AreaRegionDO> regionMap = allRegions.stream()
                .collect(Collectors.toMap(AreaRegionDO::getAdcode, region -> region));
            
            // 3. 批量构建完整名称
            List<AreaRegionDO> needUpdateList = new ArrayList<>();
            
            for (AreaRegionDO region : allRegions) {
                String fullName = buildFullName(region, regionMap);
                if (!fullName.equals(region.getFullName())) {
                    region.setFullName(fullName);
                    region.setUpdateTime(LocalDateTime.now());
                    needUpdateList.add(region);
                }
            }
            
            if (needUpdateList.isEmpty()) {
                return new RegionImportResult(0, 0, 0, System.currentTimeMillis() - startTime, "所有地区名称已是最新，无需更新");
            }
            
            // 4. 分批次批量更新
            int totalCount = needUpdateList.size();
            int successCount = 0;
            int failCount = 0;
            int batchSize = 500;
            
            for (int i = 0; i < needUpdateList.size(); i += batchSize) {
                int endIndex = Math.min(i + batchSize, needUpdateList.size());
                List<AreaRegionDO> batchList = needUpdateList.subList(i, endIndex);
                
                try {
                    areaRegionMapper.batchUpdateFullNames(batchList);
                    successCount += batchList.size();
                    log.info("批量更新地区完整名称成功，当前批次: {}-{}, 总进度: {}/{}", 
                        i + 1, endIndex, successCount, totalCount);
                } catch (Exception e) {
                    log.error("批量更新地区完整名称失败，批次: {}-{}", i + 1, endIndex, e);
                    failCount += batchList.size();
                }
            }
            
            long costTime = System.currentTimeMillis() - startTime;
            String message = String.format("完整名称填充完成！总计: %d, 成功: %d, 失败: %d, 耗时: %dms", 
                totalCount, successCount, failCount, costTime);
            
            log.info(message);
            return new RegionImportResult(totalCount, successCount, failCount, costTime, message);
            
        } catch (Exception e) {
            long costTime = System.currentTimeMillis() - startTime;
            log.error("填充完整名称失败", e);
            return new RegionImportResult(0, 0, 0, costTime, "填充失败: " + e.getMessage());
        }
    }

    /**
     * 读取JSON文件
     */
    private String readJsonFile() throws IOException {
        // 先尝试从项目根目录读取
        File rootFile = new File("country_tree.json");
        if (rootFile.exists()) {
            log.info("从项目根目录读取JSON文件: {}", rootFile.getAbsolutePath());
            return Files.readString(rootFile.toPath(), StandardCharsets.UTF_8);
        }
        
        // 如果根目录没有，尝试从classpath读取
        try {
            Resource resource = new ClassPathResource("country_tree.json");
            if (resource.exists()) {
                log.info("从classpath读取JSON文件");
                return Files.readString(resource.getFile().toPath(), StandardCharsets.UTF_8);
            }
        } catch (Exception e) {
            log.warn("从classpath读取JSON文件失败", e);
        }
        
        throw new IOException("找不到country_tree.json文件");
    }

    /**
     * 解析国家级数据
     */
    private AreaRegionDO parseCountryData(JSONObject json) {
        AreaRegionDO country = new AreaRegionDO();
        country.setAdcode(json.getString("adcode"));
        country.setName(json.getString("name"));
        country.setFullName("中华人民共和国");
        country.setLevel(0);
        country.setParentAdcode(null);
        country.setProvCode(null);
        country.setCityCode(null);
        country.setCenter(parseCenter(json.getJSONArray("center")));
        country.setBbox(parseBbox(json.getJSONArray("bbox")));
        country.setAcroutes(null);
        country.setSortOrder(1);
        country.setIsActive(true);
        country.setCreateTime(LocalDateTime.now());
        country.setUpdateTime(LocalDateTime.now());
        return country;
    }

    /**
     * 解析省级数据
     */
    private AreaRegionDO parseProvinceData(JSONObject json, int sortOrder) {
        AreaRegionDO province = new AreaRegionDO();
        province.setAdcode(json.getString("adcode"));
        province.setName(json.getString("name"));
        province.setFullName(json.getString("name"));
        province.setLevel(1);
        province.setParentAdcode("100000");
        province.setProvCode(null);
        province.setCityCode(null);
        province.setCenter(parseCenter(json.getJSONArray("center")));
        province.setBbox(parseBbox(json.getJSONArray("bbox")));
        province.setAcroutes(parseAcroutes(json.getJSONArray("acroutes")));
        province.setSortOrder(sortOrder);
        province.setIsActive(true);
        province.setCreateTime(LocalDateTime.now());
        province.setUpdateTime(LocalDateTime.now());
        return province;
    }

    /**
     * 解析市级数据
     */
    private AreaRegionDO parseCityData(JSONObject json, String provinceCode, int sortOrder) {
        AreaRegionDO city = new AreaRegionDO();
        city.setAdcode(json.getString("adcode"));
        city.setName(json.getString("name"));
        city.setFullName(json.getString("name"));
        city.setLevel(2);
        city.setParentAdcode(provinceCode);
        city.setProvCode(provinceCode);
        city.setCityCode(null);
        city.setCenter(parseCenter(json.getJSONArray("center")));
        city.setBbox(parseBbox(json.getJSONArray("bbox")));
        city.setAcroutes(parseAcroutes(json.getJSONArray("acroutes")));
        city.setSortOrder(sortOrder);
        city.setIsActive(true);
        city.setCreateTime(LocalDateTime.now());
        city.setUpdateTime(LocalDateTime.now());
        return city;
    }

    /**
     * 解析区县级数据
     */
    private AreaRegionDO parseDistrictData(JSONObject json, String provinceCode, String cityCode, int sortOrder) {
        AreaRegionDO district = new AreaRegionDO();
        district.setAdcode(json.getString("adcode"));
        district.setName(json.getString("name"));
        district.setFullName(json.getString("name"));
        district.setLevel(3);
        district.setParentAdcode(cityCode);
        
        // 正确设置 provCode 和 cityCode
        String provCodeFromJson = json.getString("provCode");
        String cityCodeFromJson = json.getString("cityCode");
        district.setProvCode(provCodeFromJson != null ? provCodeFromJson : provinceCode);
        district.setCityCode(cityCodeFromJson != null ? cityCodeFromJson : cityCode);
        
        district.setCenter(parseCenter(json.getJSONArray("center")));
        district.setBbox(parseBbox(json.getJSONArray("bbox")));
        district.setAcroutes(parseAcroutes(json.getJSONArray("acroutes")));
        district.setSortOrder(sortOrder);
        district.setIsActive(true);
        district.setCreateTime(LocalDateTime.now());
        district.setUpdateTime(LocalDateTime.now());
        return district;
    }

    /**
     * 解析中心点坐标
     */
    private String parseCenter(JSONArray centerArray) {
        if (centerArray == null || centerArray.isEmpty()) {
            return null;
        }
        return centerArray.toJSONString();
    }

    /**
     * 解析边界框
     */
    private String parseBbox(JSONArray bboxArray) {
        if (bboxArray == null || bboxArray.isEmpty()) {
            return null;
        }
        return bboxArray.toJSONString();
    }

    /**
     * 解析父级路径
     */
    private String parseAcroutes(JSONArray acroutesArray) {
        if (acroutesArray == null || acroutesArray.isEmpty()) {
            return null;
        }
        return acroutesArray.toJSONString();
    }

    /**
     * 批量插入地区数据
     */
    private void batchInsertRegions(List<AreaRegionDO> regionList) {
        if (regionList == null || regionList.isEmpty()) {
            return;
        }
        
        try {
            // 直接调用XML中定义的批量插入方法
            areaRegionMapper.batchInsertRegions(regionList);
        } catch (Exception e) {
            log.error("批量插入地区数据失败", e);
            throw new RuntimeException("批量插入失败", e);
        }
    }
    
    /**
     * 根据 acroutes 构建完整名称
     * 
     * @param region 当前地区
     * @param regionMap 所有地区的映射
     * @return 完整名称
     */
    private String buildFullName(AreaRegionDO region, Map<String, AreaRegionDO> regionMap) {
        if (region.getLevel() == 0) {
            // 国家级，直接返回名称
            return region.getName();
        }
        
        List<String> nameList = new ArrayList<>();
        
        // 解析 acroutes 获取父级路径
        if (StringUtils.hasText(region.getAcroutes())) {
            try {
                JSONArray acroutesArray = JSON.parseArray(region.getAcroutes());
                
                // 遍历父级路径，构建完整名称
                for (int i = 0; i < acroutesArray.size(); i++) {
                    String parentCode = acroutesArray.getString(i);
                    AreaRegionDO parentRegion = regionMap.get(parentCode);
                    
                    if (parentRegion != null) {
                        // 跳过国家级（全国）
                        if (parentRegion.getLevel() > 0) {
                            nameList.add(parentRegion.getName());
                        }
                    }
                }
            } catch (Exception e) {
                log.warn("解析 acroutes 失败: {}, region: {}", region.getAcroutes(), region.getName(), e);
            }
        }
        
        // 添加当前地区名称
        nameList.add(region.getName());
        
        // 拼接完整名称
        return String.join("", nameList);
    }

    /**
     * 为直辖市创建市级数据
     */
    private AreaRegionDO createMunicipalityCity(String cityCode, String provinceCode, String provinceName) {
        AreaRegionDO city = new AreaRegionDO();
        city.setAdcode(cityCode);
        city.setName(provinceName);  // 直接使用省份名称，如"北京市"
        city.setFullName(provinceName);  // 完整名称也是省份名称
        city.setLevel(2);  // 市级
        city.setParentAdcode(provinceCode);
        city.setProvCode(provinceCode);
        city.setCityCode(null);
        city.setCenter(null);  // 市级数据没有具体坐标
        city.setBbox(null);
        city.setAcroutes("[100000, " + provinceCode + "]");
        city.setSortOrder(1);
        city.setIsActive(true);
        city.setCreateTime(LocalDateTime.now());
        city.setUpdateTime(LocalDateTime.now());
        return city;
    }
}
